home *** CD-ROM | disk | FTP | other *** search
- #include <unistd.h>
- #include <stdlib.h>
- #include <stdio.h>
- #include <string.h>
- #include <errno.h>
- #include <time.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <fcntl.h>
- #include "ttyio.h"
- #include "xutil.h"
- #include "lutil.h"
- #include "session.h"
- #include "zmodem.h"
- #include "emsi.h"
-
- static int initsend(void);
- static int sendfile(char*,char*);
- static int finsend(void);
-
- static int getzrxinit(void);
- static int sendzsinit(void);
- static int zfilbuf(void);
- static int zsendfile(char*,int);
- static int zsendfdata(void);
- static int getinsync(int);
-
- static FILE *in;
- static int Test=0;
- static int Eofseen;
- static int Rxflags;
- static int Usevhdrs;
- static int Wantfcs32=TRUE;
- static int Rxbuflen;
- static int Txwindow;
- static int Tframlen;
- static int Txwcnt;
- static int blklen;
- static int blkopt;
- static int Txwspac;
- static int errors;
- static int Lastsync;
- static int bytcnt;
- static int Lrxpos=0;
- static int Lztrans=0;
- static int Lzmanag=0;
- static int Lskipnocor=0;
- static int Lzconv=0;
- static int Beenhereb4;
- static char Myattn[]={0};
- static long startime,endtime;
- #if 1
- static char *qbf=
- "The quick brown fox jumped over the lazy dog's back 1234567890\r\n";
- #else
- static char *qbf=
- "≈ ▐┴▌┴╚ └╟┴ ╓╔╠ ┬┘ ├╔╘╥╒╙? Σ┴! ε╧ ╞┴╠╪█╔╫┘╩ ▄╦┌┼═╨╠╤╥ 0123456789\r\n";
- #endif
-
- extern void get_frame_buffer(void);
-
- int zmsndfiles(file_list*);
- int zmsndfiles(lst)
- file_list *lst;
- {
- int rc,maxrc=0;
- file_list *tmpf;
-
- loginf("start %s send%s",
- (emsi_local_protos & ZAP)?"ZedZap":"Zmodem",
- lst?"":" (dummy)");
-
- get_frame_buffer();
-
- if ((rc=initsend())) return abs(rc);
- for (tmpf=lst;tmpf && (maxrc < 2);tmpf=tmpf->next)
- {
- if (tmpf->remote)
- {
- rc=sendfile(tmpf->local,tmpf->remote);
- rc=abs(rc);
- if (rc > maxrc) maxrc=rc;
- if (rc == 0) execute_disposition(tmpf);
- }
- else if (maxrc == 0) execute_disposition(tmpf);
- }
- if (maxrc < 2)
- {
- rc=finsend();
- rc=abs(rc);
- }
- if (rc > maxrc) maxrc=rc;
-
- loginf("zmodem send rc=%d",maxrc);
- return maxrc;
- }
-
- static int initsend(void)
- {
- debug(11,"initsend");
-
- PUTSTR("rz\r");
- stohdr(0L);
- zshhdr(4,ZRQINIT,Txhdr);
- if (getzrxinit())
- {
- loginf("unable to initiate zmodem send");
- return 1;
- }
- return 0;
- }
-
- static int finsend(void)
- {
- int rc;
-
- debug(11,"finsend");
- while (GETCHAR(1) >= 0) /*nothing*/;
- while (1)
- {
- stohdr(0L);
- zshhdr(4,ZFIN,Txhdr);
- if ((rc=zgethdr(Rxhdr,0)) == ZFIN) PUTSTR("OO");
- if ((rc == ZFIN) || (rc == ZCAN) || (rc < 0)) break;
- }
- return (rc != ZFIN);
- }
-
- static int sendfile(ln,rn)
- char *ln,*rn;
- {
- int rc=0;
- struct stat st;
- struct flock fl = {
- F_RDLCK,
- 0,
- 0L,
- 0L,
- 0
- };
- int bufl;
-
- if (txbuf == NULL) txbuf=xmalloc(MAXBLOCK);
-
- if ((in=fopen(ln,"r")) == NULL)
- {
- logerr("$zmsend cannot open file %s, skipping",ln);
- if (errno == ENOENT) return 0;
- else return 1;
- }
- if (fcntl(fileno(in),F_SETLK,&fl) != 0)
- {
- loginf("$zmsend cannot lock file %s, skipping",ln);
- fclose(in);
- return 1;
- }
- if (stat(ln,&st) != 0)
- {
- loginf("$cannot access \"%s\", skipping",ln);
- fclose(in);
- return 1;
- }
-
- loginf("zmodem send \"%s\" as \"%s\" (%lu bytes)",ln,rn,st.st_size);
- (void)time(&startime);
-
- sprintf(txbuf,"%s %lu %lo %o 0 0 0",
- rn,st.st_size,st.st_mtime,st.st_mode);
- bufl=strlen(txbuf);
- *(strchr(txbuf,' '))='\0'; /*hope no blanks in filename*/
-
- Eofseen = 0;
- rc=zsendfile(txbuf,bufl);
- if (rc == ZSKIP)
- {
- loginf("file %s considered normally sent",ln);
- return 0;
- }
- else if (rc == OK)
- {
- (void)time(&endtime);
- if ((startime=endtime-startime) == 0) startime=1;
- loginf("sent %lu bytes in %ld seconds (%ld cps)",
- st.st_size,startime,st.st_size/startime);
- return 0;
- }
- else return rc;
- }
-
- /*
- * Get the receiver's init parameters
- */
- int getzrxinit(void)
- {
- register n;
-
- debug(11,"getzrxinit");
- for (n=10; --n>=0; ) {
-
- switch (zgethdr(Rxhdr, 1)) {
- case ZCHALLENGE: /* Echo receiver's challenge numbr */
- stohdr(Rxpos);
- zshhdr(4, ZACK, Txhdr);
- continue;
- case ZCOMMAND: /* They didn't see out ZRQINIT */
- stohdr(0L);
- zshhdr(4, ZRQINIT, Txhdr);
- continue;
- case ZRINIT:
- Rxflags = 0377 & Rxhdr[ZF0];
- Usevhdrs = Rxhdr[ZF1] & CANVHDR;
- Txfcs32 = (Wantfcs32 && (Rxflags & CANFC32));
- Zctlesc |= Rxflags & TESCCTL;
- Rxbuflen = (0377 & Rxhdr[ZP0])+((0377 & Rxhdr[ZP1])<<8);
- if ( !(Rxflags & CANFDX))
- Txwindow = 0;
- debug(11,"Rxbuflen=%d Tframlen=%d", Rxbuflen, Tframlen);
-
- /* Override to force shorter frame length */
- if (Rxbuflen && (Rxbuflen>Tframlen) && (Tframlen>=32))
- Rxbuflen = Tframlen;
- if ( !Rxbuflen && (Tframlen>=32) && (Tframlen<=1024))
- Rxbuflen = Tframlen;
- debug(11,"Rxbuflen=%d", Rxbuflen);
-
- /* Set initial subpacket length */
- if (blklen < 1024) { /* Command line override? */
- blklen = 1024;
- }
- if (Rxbuflen && blklen>Rxbuflen)
- blklen = Rxbuflen;
- if (blkopt && blklen > blkopt)
- blklen = blkopt;
- debug(11,"Rxbuflen=%d blklen=%d", Rxbuflen, blklen);
- debug(11,"Txwindow = %u Txwspac = %d", Txwindow, Txwspac);
-
-
- if (Lztrans == ZTRLE && (Rxflags & CANRLE))
- Txfcs32 = 2;
- else
- Lztrans = 0;
-
- return (sendzsinit());
- case ZCAN:
- case ERROR:
- return ERROR;
- case HANGUP:
- return HANGUP;
- case TIMEOUT:
- stohdr(0L);
- zshhdr(4, ZRQINIT, Txhdr);
- continue;
- case ZRQINIT:
- if (Rxhdr[ZF0] == ZCOMMAND)
- continue;
- default:
- zshhdr(4, ZNAK, Txhdr);
- continue;
- }
- }
- return ERROR;
- }
-
- /* Send send-init information */
- int sendzsinit(void)
- {
- register c;
-
- debug(11,"sendzsinit");
- if (Myattn[0] == '\0' && (!Zctlesc || (Rxflags & TESCCTL)))
- return OK;
- errors = 0;
- for (;;) {
- stohdr(0L);
- if (Zctlesc) {
- Txhdr[ZF0] |= TESCCTL; zshhdr(4, ZSINIT, Txhdr);
- }
- else
- zsbhdr(4, ZSINIT, Txhdr);
- zsdata(Myattn, ZATTNLEN, ZCRCW);
- c = zgethdr(Rxhdr, 1);
- switch (c) {
- case ERROR:
- case ZCAN:
- return ERROR;
- case HANGUP:
- return HANGUP;
- case ZACK:
- return OK;
- default:
- if (++errors > 19)
- return ERROR;
- continue;
- }
- }
- }
-
- /* Fill buffer with blklen chars */
- int zfilbuf(void)
- {
- int n;
-
- debug(11,"zfilbuf (%d)",blklen);
- n = fread(txbuf, 1, blklen, in);
- if (n < blklen)
- Eofseen = 1;
- debug(11,"zfilbuf return %d",n);
- return n;
- }
-
- /* Send file name and related info */
- int zsendfile(buf, blen)
- char *buf;
- int blen;
- {
- register c;
- register long crc=-1L;
- long lastcrcrq = -1;
-
- debug(11,"zsendfile %s (%d)",buf,blen);
- for (errors=0; ++errors<11;) {
- Txhdr[ZF0] = Lzconv; /* file conversion request */
- Txhdr[ZF1] = Lzmanag; /* file management request */
- if (Lskipnocor)
- Txhdr[ZF1] |= ZMSKNOLOC;
- Txhdr[ZF2] = Lztrans; /* file transport request */
- Txhdr[ZF3] = 0;
- zsbhdr(4, ZFILE, Txhdr);
- zsdata(buf, blen, ZCRCW);
- again:
- c = zgethdr(Rxhdr, 1);
- switch (c) {
- case ZRINIT:
- while ((c = GETCHAR(5)) > 0)
- if (c == ZPAD) {
- goto again;
- }
- continue;
- case ZCAN:
- case ERROR:
- case HANGUP:
- case TIMEOUT:
- case ZABORT:
- case ZFIN:
- loginf("Got %s on pathname", frametypes[c+FTOFFSET]);
- return c;
- default:
- loginf("Got %d frame type on pathname", c);
- continue;
- case ZNAK:
- continue;
- case ZCRC:
- if (Rxpos != lastcrcrq) {
- lastcrcrq = Rxpos;
- crc = 0xFFFFFFFFL;
- fseek(in, 0L, 0);
- while (((c = getc(in)) != EOF) && --lastcrcrq)
- crc = updcrc32(c, crc);
- crc = ~crc;
- clearerr(in); /* Clear possible EOF */
- lastcrcrq = Rxpos;
- }
- stohdr(crc);
- zsbhdr(4, ZCRC, Txhdr);
- goto again;
- case ZFERR:
- case ZSKIP:
- loginf("File skipped by receiver request");
- fclose(in); return c;
- case ZRPOS:
- /*
- * Suppress zcrcw request otherwise triggered by
- * lastyunc==bytcnt
- */
- if (fseek(in, Rxpos, 0))
- return ERROR;
- Lastsync = (bytcnt = Txpos = Lrxpos = Rxpos) -1;
- return zsendfdata();
- }
- }
- fclose(in); return ERROR;
- }
-
- /* Send the data in the file */
- int zsendfdata(void)
- {
- register c=0, e, n;
- register newcnt;
- register long tcount = 0;
- int junkcount; /* Counts garbage chars received by TX */
- static int tleft = 6; /* Counter for test mode */
- int maxblklen,goodblks=0,goodneeded=8;
-
- debug(11,"zsendfdata");
-
- if (emsi_local_protos & ZAP) maxblklen=MAXBLOCK;
- else maxblklen=1024;
- if (maxblklen > Rxbuflen) maxblklen=Rxbuflen;
-
- junkcount = 0;
- Beenhereb4 = 0;
- somemore:
-
- if (0) {
-
- waitack:
- junkcount = 0;
- c = getinsync(0);
- gotack:
- switch (c) {
- default:
- case ZCAN:
- fclose(in);
- return ERROR;
- case ZSKIP:
- fclose(in);
- return c;
- case ZACK:
- case ZRPOS:
- break;
- case ZRINIT:
- fclose(in);
- return OK;
- }
- /*
- * If the reverse channel can be tested for data,
- * this logic may be used to detect error packets
- * sent by the receiver, in place of setjmp/longjmp
- * rdchk(fd) returns non 0 if a character is available
- */
- TTYWAIT(0);
- if ((c=GETCHAR(1)) == EMPTY)
- {
- TTYWAIT(1);
- }
- else if (c < 0)
- {
- return c;
- }
- else switch (c)
- {
- case CAN:
- case ZPAD:
- TTYWAIT(1);
- c = getinsync(1);
- goto gotack;
- case DC3: /* Wait a while for an XON */
- case DC3|0200:
- TTYWAIT(1);
- GETCHAR(10);
- }
-
- }
-
- newcnt = Rxbuflen;
- Txwcnt = 0;
- stohdr(Txpos);
- zsbhdr(4, ZDATA, Txhdr);
-
- /*
- * Special testing mode. This should force receiver to Attn,ZRPOS
- * many times. Each time the signal should be caught, causing the
- * file to be started over from the beginning.
- */
- if (Test) {
- if ( --tleft)
- while (tcount < 20000) {
- printf(qbf); fflush(stdout);
- tcount += strlen(qbf);
- TTYWAIT(0);
- if ((c=GETCHAR(1)) == EMPTY)
- {
- TTYWAIT(1); break;
- }
- else if (c < 0)
- {
- return c;
- }
- else switch (c)
- {
- case CAN:
- case ZPAD:
- TTYWAIT(1);
- goto waitack;
- case DC3: /* Wait for XON */
- case DC3|0200:
- TTYWAIT(1);
- GETCHAR(10);
- }
- }
- sleep(3); fflush(stdout);
- printf("\nsz: Tcount = %ld\n", tcount);
- if (tleft) {
- printf("ERROR: Interrupts Not Caught\n");
- exit(1);
- }
- exit(0);
- }
-
- do {
- n = zfilbuf();
- if (Eofseen)
- e = ZCRCE;
- else if (junkcount > 3)
- e = ZCRCW;
- else if (bytcnt == Lastsync)
- e = ZCRCW;
- else if (Rxbuflen && (newcnt -= n) <= 0)
- e = ZCRCW;
- else if (Txwindow && (Txwcnt += n) >= Txwspac) {
- Txwcnt = 0; e = ZCRCQ;
- } else
- e = ZCRCG;
- debug(11,"%7ld ZMODEM%s ",
- Txpos, Crc32t?" CRC-32":"");
- zsdata(txbuf, n, e);
- bytcnt = Txpos += n;
-
- if ((blklen < maxblklen) && (++goodblks > goodneeded))
- {
- blklen = ((blklen << 1) < maxblklen) ? blklen << 1 :
- maxblklen;
- goodblks = 0;
- }
-
- if (e == ZCRCW)
- goto waitack;
- /*
- * If the reverse channel can be tested for data,
- * this logic may be used to detect error packets
- * sent by the receiver, in place of setjmp/longjmp
- * rdchk(fd) returns non 0 if a character is available
- */
- TTYWAIT(0);
- if ((c=GETCHAR(1)) == EMPTY)
- {
- TTYWAIT(1);
- }
- else if (c < 0)
- {
- return c;
- }
- else switch (c)
- {
- case CAN:
- case ZPAD:
- TTYWAIT(1);
- c = getinsync(1);
- if (c == ZACK)
- break;
- /* zcrce - dinna wanna starta ping-pong game */
- zsdata(txbuf, 0, ZCRCE);
- goto gotack;
- case DC3: /* Wait a while for an XON */
- case DC3|0200:
- TTYWAIT(1);
- GETCHAR(10);
- default:
- ++junkcount;
- }
- if (Txwindow) {
- while ((tcount = (Txpos - Lrxpos)) >= Txwindow) {
- debug(11,"%ld window >= %u", tcount, Txwindow);
- if (e != ZCRCQ)
- zsdata(txbuf, 0, e = ZCRCQ);
- c = getinsync(1);
- if (c != ZACK) {
- zsdata(txbuf, 0, ZCRCE);
- goto gotack;
- }
- }
- debug(11,"window = %ld", tcount);
- }
- } while (!Eofseen);
-
- for (;;) {
- stohdr(Txpos);
- zsbhdr(4, ZEOF, Txhdr);
- switch (getinsync(0)) {
- case ZACK:
- continue;
- case ZRPOS:
- goto somemore;
- case ZRINIT:
- fclose(in);
- return OK;
- case ZSKIP:
- fclose(in);
- loginf("File skipped by receiver request");
- return c;
- default:
- debug(11,"Got %d trying to send end of file", c);
- fclose(in);
- return ERROR;
- }
- }
- }
-
- /*
- * Respond to receiver's complaint, get back in sync with receiver
- */
- int getinsync(flag)
- int flag;
- {
- register c;
-
- debug(11,"getinsync");
- for (;;) {
- c = zgethdr(Rxhdr, 0);
- switch (c) {
- case HANGUP:
- return HANGUP;
- case ZCAN:
- case ZABORT:
- case ZFIN:
- case ERROR:
- case TIMEOUT:
- loginf("Got %s sending data", frametypes[c+FTOFFSET]);
- return ERROR;
- case ZRPOS:
- /* ************************************* */
- /* If sending to a buffered modem, you */
- /* might send a break at this point to */
- /* dump the modem's buffer. */
- clearerr(in); /* In case file EOF seen */
- if (fseek(in, Rxpos, 0))
- return ERROR;
- Eofseen = 0;
- bytcnt = Lrxpos = Txpos = Rxpos;
- if (Lastsync == Rxpos) {
- if (++Beenhereb4 > 12) {
- loginf("Can't send block");
- return ERROR;
- }
- if (Beenhereb4 > 4)
- if (blklen > 32)
- blklen /= 2;
- }
- Lastsync = Rxpos;
- return c;
- case ZACK:
- Lrxpos = Rxpos;
- if (flag || Txpos == Rxpos)
- return ZACK;
- continue;
- case ZRINIT:
- return c;
- case ZSKIP:
- loginf("File skipped by receiver request");
- return c;
- default:
- zsbhdr(4, ZNAK, Txhdr);
- continue;
- }
- }
- }
-